package com.zhang.service;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.zhang.entity.*;
import com.zhang.entity.co.Script;
import com.zhang.entity.response.ResponseResult;
import com.zhang.entity.vo.ActionBody;
import com.zhang.entity.vo.DeleteActionBody;
import com.zhang.entity.vo.ExecuteCommandBody;
import com.zhang.exception.ServiceException;
import com.zhang.mapper.DeviceInfoMapper;
import com.zhang.mapper.ExecutionResultsMapper;
import com.zhang.mapper.ScriptTemplateMapper;
import com.zhang.util.CommandRedisUtil;
import com.zhang.util.DeviceRedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.fasterxml.jackson.databind.type.LogicalType.Map;
import static com.zhang.common.Constant.DEVICE_NOT_ONLINE;

/**
 * User: 张
 * Date: 2024-11-19
 * Time: 21:36
 * Description:
 */
@Service
public class BroadcastService {
    @Autowired
    private DeviceInfoMapper deviceInfoMapper;
    @Autowired
    private DeviceRedisUtil deviceRedisUtil;
    @Autowired
    private ScriptTemplateMapper scriptTemplateMapper;
    @Autowired
    private CommandRedisUtil commandRedisUtil;
    @Autowired
    private ExecutionResultsMapper executionResultsMapper;
    private final IoTNettyServer iotNettyServer;

    @Autowired
    public BroadcastService(IoTNettyServer iotNettyServer) {
        this.iotNettyServer = iotNettyServer;
    }

    public void executeCommand(ExecuteCommandBody executeCommandBody) {
        String serverIp = deviceInfoMapper.getDeviceInfoById(executeCommandBody.getServerId()).getServerIp();
        String channelId = deviceRedisUtil.getChannelId(serverIp);
        if (channelId == null) throw new ServiceException(DEVICE_NOT_ONLINE);
        ScriptTemplate scriptTemplate = scriptTemplateMapper.getScriptTemplateById(executeCommandBody.getScripTemplateId());

        String executeId = IdUtil.fastSimpleUUID();
        // todo 将 执行任务的机器ip 与 执行任务的id 绑定放入redis
        commandRedisUtil.addCommand(serverIp, executeId);
        // todo 通过netty将任务发送给设备
        CommonTemplate commonTemplate = new CommonTemplate(executeId,executeCommandBody.getExecuteFrequency(),scriptTemplate.getScriptContent());
        iotNettyServer.broadcastMessage(channelId, JSON.toJSONString(commonTemplate));
        // todo 记录本次发送操作的信息
        executionResultsMapper.insertExecutionResults(
                new ExecutionResults()
                        .setExecutionScript(JSON.toJSONString(commonTemplate))
                        .setExecutionTime(new Date())
                        .setServerIp(serverIp)
                        .setChannelId(channelId)
        );
    }

    public Boolean addScriptTemplate(ScriptTemplate scriptTemplate){
        return scriptTemplateMapper.addScriptTemplate(scriptTemplate) > 0;
    }

    public PageInfo<ScriptTemplate> getScriptTemplate(ScriptTemplate scriptTemplate, Integer pageNum, Integer pageSize){
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(scriptTemplateMapper.getScriptTemplate(scriptTemplate));
    }

    public Boolean updateScriptTemplate(ScriptTemplate scriptTemplate){
        return scriptTemplateMapper.updateScriptTemplate(scriptTemplate.getScriptContent(), scriptTemplate.getScriptId()) > 0;
    }

    public Boolean deleteScriptTemplate(ScriptTemplate scriptTemplate){
        return scriptTemplateMapper.deleteScriptTemplate(scriptTemplate.getScriptId()) > 0;
    }

    public Boolean addAction(ActionBody actionBody){
        ScriptTemplate template = scriptTemplateMapper.getScriptTemplateById(Integer.parseInt(actionBody.getTemplateId()));
        Node tree = new Gson().fromJson(template.getScriptContent(), Node.class);
        addChildren(tree, actionBody.getNode(), actionBody.getParentNodeId());
        return  scriptTemplateMapper.updateScriptTemplate(new Gson().toJson(tree), Integer.parseInt(actionBody.getTemplateId())) > 0;
    }

    public void addChildren(Node tree,Node children,String parentNodeId){
        if (tree.getId().equalsIgnoreCase(parentNodeId)){
            tree.addChild(children);
        }
        for (Node node : tree.getChildren()) {
            addChildren(node,children,parentNodeId);
        }
    }

    public Boolean deleteAction(DeleteActionBody deleteActionBody){
        ScriptTemplate template = scriptTemplateMapper.getScriptTemplateById(Integer.parseInt(deleteActionBody.getTemplateId()));
        Node tree = new Gson().fromJson(template.getScriptContent(), Node.class);
        deleteChildren(tree,deleteActionBody.getNodeId());
        return scriptTemplateMapper.updateScriptTemplate(new Gson().toJson(tree), Integer.parseInt(deleteActionBody.getTemplateId())) > 0;
    }

    public void deleteChildren(Node tree,String nodeId){
        for (Node node : tree.getChildren()) {
            if (node.getId().equalsIgnoreCase(nodeId)){
                tree.removeChild(nodeId);
                break;
            }
            deleteChildren(node,nodeId);
        }
    }

}
